#include <X11/Xlib.h>
#include <iostream>
#include <stdlib.h>

int main()
{
    // 获取根窗口
    Display *display = XOpenDisplay(nullptr);
    printf("display = %s\n", display);
    auto root_window = DefaultRootWindow(display);

    Window root_return, parent_return;
    Window *child_list = nullptr;
    unsigned int child_num = 0;
    // 函数详细说明见xlib文档：https://tronche.com/gui/x/xlib/window-information/XQueryTree.html
    // 该函数会返回父窗口的子窗口列表child_list，因为这里用的是当前桌面的根窗口作为父窗口，所以会返回所有子窗口
    // 注意：窗口顺序(z-order)为自底向上
    XQueryTree(display, root_window, &root_return, &parent_return, &child_list, &child_num);

    for (unsigned int i = 0; i < child_num; ++i)
    {
        XWindowAttributes attrs;
        // 获取窗口的一些参数
        XGetWindowAttributes(display, child_list[i], &attrs);

        // map_state 可以判断窗口是否可见
        // 三个状态：IsUnmapped, IsUnviewable, IsViewable
        // IsViewable 即为可见窗口
        // 注意：窗口被其他窗口完全遮挡看不到也是 IsViewable ，可以用窗口z-order结合位置尺寸判断这种情况
        if (attrs.map_state == 2)
        { // IsViewable
            char *buffer = nullptr;
            // 获取窗口名字，获取成功后buffer才会有值
            XFetchName(display, child_list[i], &buffer);

            // 打印窗口的位置、尺寸和名字
            std::cout << "#" << i << ": "
                      << "(" << attrs.x << ", " << attrs.y << ", " << attrs.width << "x" << attrs.height << ") \"" << (buffer ? buffer : "") << "\"" << std::endl;
            // 注意释放
            XFree(buffer);
        }
    }

    // 注意释放资源
    XFree(child_list);
    XCloseDisplay(display);

    return 0;
}
